package com.pithypan.controller;

import com.pithypan.common.*;
import com.pithypan.common.exceptionHandler.MyException;
import com.pithypan.common.utils.R;
import com.pithypan.common.utils.RedisUtils;
import com.pithypan.common.utils.StringTools;
import com.pithypan.convert.FileInfoConvert;
import com.pithypan.dto.DownloadFileDto;
import com.pithypan.entity.FileInfo;
import com.pithypan.entity.UserInfo;
import com.pithypan.mapper.FileInfoMapper;
import com.pithypan.service.FileInfoService;
import com.pithypan.vo.FileInfoQuery;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.List;

/**
 * 通用父类
 */
public class CommonFileController {

    @Value("${project.folder}")
    private String projectFolder;      //存储文件的路径
    @Autowired
    private FileInfoService fileInfoService;
    @Resource
    private RedisUtils redisUtils;

    private static final Logger logger = LoggerFactory.getLogger(CommonFileController.class);


    //读取图片文件的预览图
    public void getImage(HttpServletResponse response, String imageFolder, String imageName) {
        //判断源 文件路径 和 源文件名 是否有异常
        if (StringTools.isEmpty(imageFolder) || StringTools.isEmpty(imageName) || !StringTools.pathIsOk(imageFolder) || !StringTools.pathIsOk(imageName)) {
            return;
        }

        String filePath = projectFolder + "/file/" + imageFolder + "/" + imageName;  //图片路径
        String imageSuffix = StringTools.getFileSuffix(imageName);                   //获取后缀名
        imageSuffix = imageSuffix.replace(".", "");                //把 . 字符去掉
        String contentType = "image/" + imageSuffix;
        response.setContentType(contentType);                                        //响应体数据格式
        response.setHeader("Cache-Control", "max-age=2592000");                 //缓存时间
        readFile(response, filePath);                                                //通过字节流读取头像，并写入网页中
    }


    //视频文件 或 文本文件 预览
    public void getFile(HttpServletResponse response, String fileId, String userId) {
        String filePath = null;        //视频文件的.m3u8文件 或 .ts文件的绝对路径

        if (fileId.endsWith(".ts")) {  //测试字符串是否以指定的后缀结束
            //读取视频.ts片段
            String[] tsArray = fileId.split("_"); //切割字符串，不会包含“_”
            String realFileId = tsArray[0];

            FileInfo fileInfo = fileInfoService.getFileInfoByFileIdAndUserId(realFileId, userId);
            if (fileInfo == null) {
                return;
            }

            String fileNameNoSuffix = StringTools.getFileNameNoSuffix(fileInfo.getFilePath());
            filePath = projectFolder + "/file/" + fileNameNoSuffix + "/" + fileId;

        } else {
            FileInfo fileInfo = fileInfoService.getFileInfoByFileIdAndUserId(fileId, userId);
            if (fileInfo == null) {
                return;
            }

            if (fileInfo.getFileCategory().equals(FileCategoryEnums.VIDEO.getCategory())) {
                //读取视频.m3u8文件
                String fileNameNoSuffix = StringTools.getFileNameNoSuffix(fileInfo.getFilePath());
                filePath = projectFolder + "/file/" + fileNameNoSuffix + "/" + Constants.M3U8_NAME; //m3u8文件绝对路径
            } else {
                //读取其它文本文件
                filePath = projectFolder + "/file/" + fileInfo.getFilePath();
            }

            File file = new File(filePath);
            if (!file.exists()) {
                return;
            }
        }

        readFile(response, filePath);       //通过字节流读取文件
    }


    //根据 id串 获取相对应的目录
    protected R getFolderInfo(String userId, String path) {
        String[] pathArray = path.split("/");
        FileInfoQuery infoQuery = new FileInfoQuery();
        infoQuery.setUserId(userId);
        infoQuery.setFolderType(FileFolderTypeEnums.FOLDER.getType());
        infoQuery.setDelFlag(FileDelFlagEnums.USING.getFlag());
        infoQuery.setFileIdArray(pathArray);
        //StringUtils.join()：拆分数组中的元素，以逗号分隔，进行字符串拼接
        //SQL：field(file_id, "...", "...") -- field根据file_id字段进行自定义排序(根据file_id后面跟着的id顺序排序)，id必需由双引号括住，所以正文进行了转义
        String orderBy = "field(file_id,\"" + StringUtils.join(pathArray, "\",\"") + "\")";
        infoQuery.setOrderBy(orderBy);
        List<FileInfo> list = fileInfoService.findListByParam(infoQuery);
        return R.ok().data("folderList", FileInfoConvert.INSTANCE.listentity2vo(list));
    }


    //创建下载
    protected R createDownloadUrl(String userId, String fileId) {
        FileInfo fileInfo = fileInfoService.getFileInfoByFileIdAndUserId(fileId, userId);
        if (fileInfo == null) {
            throw new MyException(ResponseCodeEnum.CODE_605.getCode(), ResponseCodeEnum.CODE_605.getMsg());
        }
        if (FileFolderTypeEnums.FOLDER.getType().equals(fileInfo.getFolderType())) {
            throw new MyException(ResponseCodeEnum.CODE_605.getCode(), ResponseCodeEnum.CODE_605.getMsg());
        }

        //创建下载文件
        String code = StringTools.getRandomString(Constants.LENGTH_50);
        DownloadFileDto fileDto = new DownloadFileDto();
        fileDto.setDownloadCode(code);
        fileDto.setFileName(fileInfo.getFileName());
        fileDto.setFilePath(fileInfo.getFilePath());

        //redis
        redisUtils.setex(Constants.REDIS_KEY_DOWNLOAD + code, fileDto, Constants.REDIS_KEY_FIVE_MIN);

        return R.ok().data("downloadDto", fileDto);
    }


    //文件下载
    protected void download(HttpServletRequest request, HttpServletResponse response, String code) throws Exception {
        //从redis获取下载文件
        DownloadFileDto downloadFileDto = (DownloadFileDto) redisUtils.get(Constants.REDIS_KEY_DOWNLOAD + code);
        if (downloadFileDto == null) {
            return;
        }

        String filePath = projectFolder + "/file/" + downloadFileDto.getFilePath(); //文件路径
        String fileName = downloadFileDto.getFileName();
        response.setContentType("application/x-msdownload; charset=UTF-8");         //响应体数据格式

        if (request.getHeader("User-Agent").toLowerCase().indexOf("msie") > 0) {  //IE浏览器
            fileName = URLEncoder.encode(fileName, "UTF-8");
        } else {
            fileName = new String(fileName.getBytes("UTF-8"), "ISO8859-1");
        }

        response.setHeader("Content-Disposition", "attachment;filename=\"" + fileName + "\"");
        readFile(response, filePath);
    }


//-------------------------------------------------------------------------------------------


    //IO读取图片文件
    protected void readFile(HttpServletResponse response, String filePath) {
        if (!StringTools.pathIsOk(filePath)) {  //判断路径是否合理
            return;
        }

        OutputStream out = null;
        FileInputStream in = null;
        try {
            File file = new File(filePath);
            if (!file.exists()) {
                return;
            }

            byte[] byteData = new byte[1024];
            in = new FileInputStream(file);     //创建读取的文件流
            out = response.getOutputStream();   //由response创建out流
            int len = 0;
            while ((len = in.read(byteData)) != -1) { //读取1024个字节（read方法返回实际读取到的字节数，到达文件末尾时返回-1）
                out.write(byteData, 0, len);
            }
            out.flush();
        } catch (Exception e) {
            logger.error("读取文件失败", e);
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    logger.error("out -- IO异常", e);
                }
            }
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    logger.error("in -- IO异常", e);
                }
            }
        }
    }

}
